// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
//
// ███╗   ██╗ ██████╗ ████████╗██╗ ██████╗███████╗
// ████╗  ██║██╔═══██╗╚══██╔══╝██║██╔════╝██╔════╝
// ██╔██╗ ██║██║   ██║   ██║   ██║██║     █████╗
// ██║╚██╗██║██║   ██║   ██║   ██║██║     ██╔══╝
// ██║ ╚████║╚██████╔╝   ██║   ██║╚██████╗███████╗
// ╚═╝  ╚═══╝ ╚═════╝    ╚═╝   ╚═╝ ╚═════╝╚══════╝
// ------------------------------------------------
//
// This file is automatically generated.
// Please do not edit these files manually.
//
// ------------------------------------------------

#nullable restore

using Elastic.Clients.Elasticsearch.Serverless.Fluent;
using Elastic.Clients.Elasticsearch.Serverless.Serialization;
using Elastic.Transport;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Elastic.Clients.Elasticsearch.Serverless;

[JsonConverter(typeof(SortOptionsConverter))]
public sealed partial class SortOptions
{
	internal SortOptions(string variantName, object variant)
	{
		if (variantName is null)
			throw new ArgumentNullException(nameof(variantName));
		if (variant is null)
			throw new ArgumentNullException(nameof(variant));
		if (string.IsNullOrWhiteSpace(variantName))
			throw new ArgumentException("Variant name must not be empty or whitespace.");
		VariantName = variantName;
		Variant = variant;
	}

	internal SortOptions(Elastic.Clients.Elasticsearch.Serverless.Field field, object variant)
	{
		if (field is null)
			throw new ArgumentNullException(nameof(field));
		if (variant is null)
			throw new ArgumentNullException(nameof(variant));
		AdditionalPropertyName = field;
		Variant = variant;
	}

	internal object Variant { get; }
	internal string VariantName { get; }
	internal Elastic.Clients.Elasticsearch.Serverless.Field? AdditionalPropertyName { get; }

	public static SortOptions Doc(Elastic.Clients.Elasticsearch.Serverless.ScoreSort scoreSort) => new SortOptions("_doc", scoreSort);
	public static SortOptions GeoDistance(Elastic.Clients.Elasticsearch.Serverless.GeoDistanceSort geoDistanceSort) => new SortOptions("_geo_distance", geoDistanceSort);
	public static SortOptions Score(Elastic.Clients.Elasticsearch.Serverless.ScoreSort scoreSort) => new SortOptions("_score", scoreSort);
	public static SortOptions Script(Elastic.Clients.Elasticsearch.Serverless.ScriptSort scriptSort) => new SortOptions("_script", scriptSort);
	public static SortOptions Field(Elastic.Clients.Elasticsearch.Serverless.Field field, Elastic.Clients.Elasticsearch.Serverless.FieldSort fieldSort) => new SortOptions(field, fieldSort);
}

public sealed partial class SortOptionsDescriptor<TDocument> : SerializableDescriptor<SortOptionsDescriptor<TDocument>>
{
	internal SortOptionsDescriptor(Action<SortOptionsDescriptor<TDocument>> configure) => configure.Invoke(this);

	public SortOptionsDescriptor() : base()
	{
	}

	private bool ContainsVariant { get; set; }
	private string ContainedVariantName { get; set; }
	private object Variant { get; set; }
	private Descriptor Descriptor { get; set; }
	private Elastic.Clients.Elasticsearch.Serverless.Field AdditionalPropertyName { get; set; }
	private Elastic.Clients.Elasticsearch.Serverless.FieldSort AdditionalPropertyValue { get; set; }

	private SortOptionsDescriptor<TDocument> Set<T>(Action<T> descriptorAction, string variantName) where T : Descriptor
	{
		AdditionalPropertyValue = null;
		AdditionalPropertyName = null;
		ContainedVariantName = variantName;
		ContainsVariant = true;
		var descriptor = (T)Activator.CreateInstance(typeof(T), true);
		descriptorAction?.Invoke(descriptor);
		Descriptor = descriptor;
		return Self;
	}

	private SortOptionsDescriptor<TDocument> Set(object variant, string variantName)
	{
		AdditionalPropertyValue = null;
		AdditionalPropertyName = null;
		Variant = variant;
		ContainedVariantName = variantName;
		ContainsVariant = true;
		return Self;
	}

	private SortOptionsDescriptor<TDocument> Set<T>(Action<T> descriptorAction, Elastic.Clients.Elasticsearch.Serverless.Field variantName) where T : Descriptor
	{
		var descriptor = (T)Activator.CreateInstance(typeof(T), true);
		descriptorAction?.Invoke(descriptor);
		Descriptor = descriptor;
		ContainedVariantName = null;
		Variant = null;
		AdditionalPropertyValue = null;
		AdditionalPropertyName = variantName;
		ContainsVariant = true;
		return Self;
	}

	private SortOptionsDescriptor<TDocument> Set(Elastic.Clients.Elasticsearch.Serverless.FieldSort variant, Elastic.Clients.Elasticsearch.Serverless.Field variantName)
	{
		ContainedVariantName = null;
		Variant = null;
		AdditionalPropertyValue = variant;
		AdditionalPropertyName = variantName;
		ContainsVariant = true;
		return Self;
	}

	public SortOptionsDescriptor<TDocument> Doc(ScoreSort scoreSort) => Set(scoreSort, "_doc");
	public SortOptionsDescriptor<TDocument> Doc(Action<ScoreSortDescriptor> configure) => Set(configure, "_doc");
	public SortOptionsDescriptor<TDocument> GeoDistance(GeoDistanceSort geoDistanceSort) => Set(geoDistanceSort, "_geo_distance");
	public SortOptionsDescriptor<TDocument> GeoDistance(Action<GeoDistanceSortDescriptor<TDocument>> configure) => Set(configure, "_geo_distance");
	public SortOptionsDescriptor<TDocument> Score(ScoreSort scoreSort) => Set(scoreSort, "_score");
	public SortOptionsDescriptor<TDocument> Score(Action<ScoreSortDescriptor> configure) => Set(configure, "_score");
	public SortOptionsDescriptor<TDocument> Script(ScriptSort scriptSort) => Set(scriptSort, "_script");
	public SortOptionsDescriptor<TDocument> Script(Action<ScriptSortDescriptor<TDocument>> configure) => Set(configure, "_script");
	public SortOptionsDescriptor<TDocument> Field(Elastic.Clients.Elasticsearch.Serverless.Field field) => Set(FieldSort.Empty, field);
	public SortOptionsDescriptor<TDocument> Field(Expression<Func<TDocument, object>> field) => Set(FieldSort.Empty, field);
	public SortOptionsDescriptor<TDocument> Field(Elastic.Clients.Elasticsearch.Serverless.Field field, Elastic.Clients.Elasticsearch.Serverless.FieldSort sort) => Set(sort, field);
	public SortOptionsDescriptor<TDocument> Field(Expression<Func<TDocument, object>> field, Elastic.Clients.Elasticsearch.Serverless.FieldSort sort) => Set(sort, field);
	public SortOptionsDescriptor<TDocument> Field(Elastic.Clients.Elasticsearch.Serverless.Field field, Action<FieldSortDescriptor<TDocument>> configure) => Set(configure, field);
	public SortOptionsDescriptor<TDocument> Field(Expression<Func<TDocument, object>> field, Action<FieldSortDescriptor<TDocument>> configure) => Set(configure, field);

	protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions options, IElasticsearchClientSettings settings)
	{
		if (!ContainsVariant)
		{
			writer.WriteNullValue();
			return;
		}

		var fieldName = ContainedVariantName;
		if (AdditionalPropertyName is IUrlParameter urlParameter)
		{
			fieldName = urlParameter.GetString(settings);
		}

		if ((Variant is not null && Variant.Equals(FieldSort.Empty)) || (AdditionalPropertyValue is not null && AdditionalPropertyValue.Equals(FieldSort.Empty)))
		{
			writer.WriteStringValue(fieldName);
			return;
		}

		writer.WriteStartObject();
		writer.WritePropertyName(fieldName);
		if (Variant is not null)
		{
			JsonSerializer.Serialize(writer, Variant, Variant.GetType(), options);
			writer.WriteEndObject();
			return;
		}

		if (AdditionalPropertyValue is not null)
		{
			JsonSerializer.Serialize(writer, AdditionalPropertyValue, options);
			writer.WriteEndObject();
			return;
		}

		JsonSerializer.Serialize(writer, Descriptor, Descriptor.GetType(), options);
		writer.WriteEndObject();
	}
}

public sealed partial class SortOptionsDescriptor : SerializableDescriptor<SortOptionsDescriptor>
{
	internal SortOptionsDescriptor(Action<SortOptionsDescriptor> configure) => configure.Invoke(this);

	public SortOptionsDescriptor() : base()
	{
	}

	private bool ContainsVariant { get; set; }
	private string ContainedVariantName { get; set; }
	private object Variant { get; set; }
	private Descriptor Descriptor { get; set; }
	private Elastic.Clients.Elasticsearch.Serverless.Field AdditionalPropertyName { get; set; }
	private Elastic.Clients.Elasticsearch.Serverless.FieldSort AdditionalPropertyValue { get; set; }

	private SortOptionsDescriptor Set<T>(Action<T> descriptorAction, string variantName) where T : Descriptor
	{
		AdditionalPropertyValue = null;
		AdditionalPropertyName = null;
		ContainedVariantName = variantName;
		ContainsVariant = true;
		var descriptor = (T)Activator.CreateInstance(typeof(T), true);
		descriptorAction?.Invoke(descriptor);
		Descriptor = descriptor;
		return Self;
	}

	private SortOptionsDescriptor Set(object variant, string variantName)
	{
		AdditionalPropertyValue = null;
		AdditionalPropertyName = null;
		Variant = variant;
		ContainedVariantName = variantName;
		ContainsVariant = true;
		return Self;
	}

	private SortOptionsDescriptor Set<T>(Action<T> descriptorAction, Elastic.Clients.Elasticsearch.Serverless.Field variantName) where T : Descriptor
	{
		var descriptor = (T)Activator.CreateInstance(typeof(T), true);
		descriptorAction?.Invoke(descriptor);
		Descriptor = descriptor;
		ContainedVariantName = null;
		Variant = null;
		AdditionalPropertyValue = null;
		AdditionalPropertyName = variantName;
		ContainsVariant = true;
		return Self;
	}

	private SortOptionsDescriptor Set(Elastic.Clients.Elasticsearch.Serverless.FieldSort variant, Elastic.Clients.Elasticsearch.Serverless.Field variantName)
	{
		ContainedVariantName = null;
		Variant = null;
		AdditionalPropertyValue = variant;
		AdditionalPropertyName = variantName;
		ContainsVariant = true;
		return Self;
	}

	public SortOptionsDescriptor Doc(ScoreSort scoreSort) => Set(scoreSort, "_doc");
	public SortOptionsDescriptor Doc(Action<ScoreSortDescriptor> configure) => Set(configure, "_doc");
	public SortOptionsDescriptor GeoDistance(GeoDistanceSort geoDistanceSort) => Set(geoDistanceSort, "_geo_distance");
	public SortOptionsDescriptor GeoDistance(Action<GeoDistanceSortDescriptor> configure) => Set(configure, "_geo_distance");
	public SortOptionsDescriptor GeoDistance<TDocument>(Action<GeoDistanceSortDescriptor<TDocument>> configure) => Set(configure, "_geo_distance");
	public SortOptionsDescriptor Score(ScoreSort scoreSort) => Set(scoreSort, "_score");
	public SortOptionsDescriptor Score(Action<ScoreSortDescriptor> configure) => Set(configure, "_score");
	public SortOptionsDescriptor Script(ScriptSort scriptSort) => Set(scriptSort, "_script");
	public SortOptionsDescriptor Script(Action<ScriptSortDescriptor> configure) => Set(configure, "_script");
	public SortOptionsDescriptor Script<TDocument>(Action<ScriptSortDescriptor<TDocument>> configure) => Set(configure, "_script");
	public SortOptionsDescriptor Field(Elastic.Clients.Elasticsearch.Serverless.Field field) => Set(FieldSort.Empty, field);
	public SortOptionsDescriptor Field(Elastic.Clients.Elasticsearch.Serverless.Field field, Elastic.Clients.Elasticsearch.Serverless.FieldSort sort) => Set(sort, field);
	public SortOptionsDescriptor Field(Elastic.Clients.Elasticsearch.Serverless.Field field, Action<FieldSortDescriptor> configure) => Set(configure, field);

	protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions options, IElasticsearchClientSettings settings)
	{
		if (!ContainsVariant)
		{
			writer.WriteNullValue();
			return;
		}

		var fieldName = ContainedVariantName;
		if (AdditionalPropertyName is IUrlParameter urlParameter)
		{
			fieldName = urlParameter.GetString(settings);
		}

		if ((Variant is not null && Variant.Equals(FieldSort.Empty)) || (AdditionalPropertyValue is not null && AdditionalPropertyValue.Equals(FieldSort.Empty)))
		{
			writer.WriteStringValue(fieldName);
			return;
		}

		writer.WriteStartObject();
		writer.WritePropertyName(fieldName);
		if (Variant is not null)
		{
			JsonSerializer.Serialize(writer, Variant, Variant.GetType(), options);
			writer.WriteEndObject();
			return;
		}

		if (AdditionalPropertyValue is not null)
		{
			JsonSerializer.Serialize(writer, AdditionalPropertyValue, options);
			writer.WriteEndObject();
			return;
		}

		JsonSerializer.Serialize(writer, Descriptor, Descriptor.GetType(), options);
		writer.WriteEndObject();
	}
}